package cn.stylefeng.guns.cloud.workflow.modular.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.stylefeng.guns.cloud.libs.context.auth.LoginContext;
import cn.stylefeng.guns.cloud.libs.mp.page.PageFactory;
import cn.stylefeng.guns.cloud.model.page.PageResult;
import cn.stylefeng.guns.cloud.workflow.api.entity.ActBaseEntity;
import cn.stylefeng.guns.cloud.workflow.modular.model.params.ApproveParam;
import cn.stylefeng.guns.cloud.workflow.modular.model.params.TaskParam;
import cn.stylefeng.guns.cloud.workflow.modular.model.result.TodoTaskResult;
import cn.stylefeng.guns.cloud.workflow.modular.service.ActBaseService;
import cn.stylefeng.guns.cloud.workflow.modular.service.ApproveHistoryService;
import cn.stylefeng.guns.cloud.workflow.modular.service.TodoTaskService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 待办任务 服务实现类
 *
 * @Author xuyuxiang
 * @Date 2019/11/14 16:32
 **/
@Service
public class TodoTaskServiceImpl<T extends ActBaseEntity> implements TodoTaskService<T> {

    private final String APPLY_USER_NAME = "applyUserName";

    private final String APPLY_DATE = "applyDate";

    private final String APPLY_USER_ID = "applyUserId";

    @Autowired
    private TaskService taskService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ApproveHistoryService approveHistoryService;

    @Autowired
    ProcessEngineConfiguration processEngineConfiguration;

    @Autowired
    private ActBaseService actBaseService;

    /**
     * 查询我的待办任务列表
     *
     * @Author xuyuxiang
     * @Date 2019/10/30 17:23
     **/
    @Override
    public PageResult list(TaskParam taskParam) {

        Page pageContext = this.getPageContext();

        String userIdString = String.valueOf(LoginContext.me().getAccountId());

        Set<Long> roleIdsList = LoginContext.me().getLoginUser().getRoleIds();

        List<String> roleIdsString = new ArrayList<>();
        for (Long roleId : roleIdsList) {
            String roleIdString = String.valueOf(roleId);
            roleIdsString.add(roleIdString);
        }

        //待办人或候选人
        taskParam.setAssigneeOrCandidateUserId(userIdString);
        //候选组
        taskParam.setCandidateGroupIdList(roleIdsString);

        TaskQuery taskQuery = this.getTodoTaskQuery(taskParam);

        List<Task> taskList = taskQuery.listPage((int) pageContext.getSize() * ((int) pageContext.getCurrent() - 1),
                (int) pageContext.getSize());
        long count = taskQuery.count();

        List<TodoTaskResult> todoTaskResultList = this.copyTodoTaskListInfo(taskList);

        pageContext.setRecords(todoTaskResultList);
        pageContext.setTotal(count);
        return new PageResult(pageContext);
    }

    /**
     * 获取待办任务TaskQuery
     *
     * @Author xuyuxiang
     * @Date 2019/10/31 15:11
     **/
    public TaskQuery getTodoTaskQuery(TaskParam taskParam) {

        //获取TaskQuery
        TaskQuery taskQuery = taskService.createTaskQuery();

        String processName = taskParam.getProcessName();

        //根据流程名称查询
        if (ObjectUtil.isNotEmpty(processName)) {
            //根据流程名称查询流程定义实例集合
            ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionNameLike("%" + processName + "%");
            List<ProcessDefinition> processDefinitionList = processDefinitionQuery.list();
            //获取流程定义实例的key集合
            Set<String> processKeySet = new HashSet<>();
            for (ProcessDefinition processDefinition : processDefinitionList) {
                String key = processDefinition.getKey();
                processKeySet.add(key);
            }
            List<String> processKeyList = new ArrayList<>(processKeySet);
            taskQuery.processDefinitionKeyIn(processKeyList);
        }

        //根据申请人查询
        String applyUserId = taskParam.getApplyUserId();

        if (ObjectUtil.isNotEmpty(applyUserId)) {
            //TODO
        }

        String assigneeOrCandidateUserId = taskParam.getAssigneeOrCandidateUserId();

        List<String> candidateGroupIdList = taskParam.getCandidateGroupIdList();

        taskQuery.taskCandidateOrAssigned(assigneeOrCandidateUserId).taskCandidateGroupIn(candidateGroupIdList);

        //查询流程为未挂起的
        taskQuery.active();

        return taskQuery;
    }


    /**
     * 将Task集合转换为TaskModel集合（待办任务）
     *
     * @Author xuyuxiang
     * @Date 2019/10/31 14:17
     **/
    public List<TodoTaskResult> copyTodoTaskListInfo(List<Task> taskList) {
        //返回的TaskModel集合
        List<TodoTaskResult> todoTaskResultList = new ArrayList<>();

        for (Task task : taskList) {
            //任务id
            String taskId = task.getId();
            //任务名称
            String taskName = task.getName();
            Map<String, Object> variables = taskService.getVariables(taskId);
            //申请人id
            String applyUserId = variables.get(APPLY_USER_ID).toString();
            //申请人姓名
            String applyUserName = (String) variables.get(APPLY_USER_NAME);
            //申请人时间
            String applyDate = (String) variables.get(APPLY_DATE);
            //待办人id
            String taskAssignee = task.getAssignee();
            //待办人姓名
            String taskAssigneeUserName = "-";

            //待办人不存在，表示该任务为组任务,则不展示待办人姓名,只有待办人为具体人员时才展示
            if (ObjectUtil.isNotEmpty(taskAssignee)) {
                //待办人姓名
                taskAssigneeUserName = actBaseService.getNameByUserId(taskAssignee);
            }

            //委托人id
            String taskOwner = task.getOwner();
            //委托人姓名
            String taskOwnerName = "-";
            if (ObjectUtil.isNotEmpty(taskOwner)) {
                //如果委托人不为空,则展示
                taskOwnerName = actBaseService.getNameByUserId(taskOwner);
            } else {
                taskOwner = "-";
            }
            //获取流程定义id
            String processDefinitionId = task.getProcessDefinitionId();
            //获取流程定义实例
            ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId);
            //获取流程名称
            String processDefinitionName = processDefinition.getName();
            //流程实例id
            String processInstanceId = task.getProcessInstanceId();
            //待办任务标题
            String taskTitle = processDefinitionName + "(" + applyUserName + " " + applyDate + ")";

            //创建TodoTaskResult
            TodoTaskResult taskResult = new TodoTaskResult();

            taskResult.setTaskId(taskId);
            taskResult.setProcessDefinitionId(processDefinitionId);
            taskResult.setProcessInstanceId(processInstanceId);
            taskResult.setTaskTitle(taskTitle);
            taskResult.setProcessName(processDefinitionName);
            taskResult.setApplyUserId(applyUserId);
            taskResult.setApplyUserName(applyUserName);
            taskResult.setApplyDate(applyDate);
            taskResult.setApproveProcess(taskName);
            taskResult.setTaskAssigneeUserId(taskAssignee);
            taskResult.setTaskAssigneeUserName(taskAssigneeUserName);
            taskResult.setTaskOwnerUserId(taskOwner);
            taskResult.setTaskOwnerName(taskOwnerName);

            todoTaskResultList.add(taskResult);
        }
        return todoTaskResultList;
    }


    /**
     * 审批
     *
     * @Author xuyuxiang
     * @Date 2019/11/4 14:36
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doneTask(ApproveParam approveParam) {

        String processInstanceId = approveParam.getProcessInstanceId();

        //根据processInstanceId获取Task，此时Task一定处于运行中
        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        //获取taskId
        String taskId = task.getId();
        //完成审批时将审批记录保存
        Map<String, Object> paramMap = approveHistoryService.getLatestApproveInfo(approveParam);

        String taskOwner = task.getOwner();
        //待办人
        String taskAssignee = task.getAssignee();
        if (ObjectUtil.isNotEmpty(taskOwner)) {
            //若任务所属人不为空，且是自己（任务被委托人操作后，任务回归到原待办人，owner不会清空），则正常办理
            if (taskOwner.equals(taskAssignee)) {
                taskService.complete(taskId, paramMap);
            } else {
                //若任务所属人不为空，但不是自己，表明该任务为其他人委托办理的，则调用委托方法
                taskService.resolveTask(taskId, paramMap);
            }
        } else {
            //若任务所属人为空,则正常办理（当任务没有被委托时，owner默认为空,当任务被委托了，则原待办人变为owner）
            taskService.complete(taskId, paramMap);
        }
    }

    /**
     * 重新申请或取消申请
     *
     * @Author xuyuxiang
     * @Date 2019/11/5 16:43
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reStartOrCancelRequire(T entity, Integer approveOperate) {
        String processInstanceId = entity.getProcessInstanceId();

        //根据processInstanceId获取Task
        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();

        //获取taskId
        String taskId = task.getId();

        ApproveParam approveParam = new ApproveParam();
        approveParam.setProcessInstanceId(processInstanceId);
        approveParam.setApproveOperate(approveOperate);
        approveParam.setApproveNote("-");

        //将审批记录保存
        Map<String, Object> paramMap = approveHistoryService.getLatestApproveInfo(approveParam);

        //更新实体参数
        paramMap.put("entity", entity);
        taskService.complete(taskId, paramMap);
    }


    /**
     * 委托（被委托人处理后任务依然转给委托人，只是多一条审批记录）
     *
     * @Author xuyuxiang
     * @Date 2019/11/7 17:11
     **/
    public void entrust(TaskParam taskParam) {

        String processInstanceId = taskParam.getProcessInstanceId();

        String assigneeOrCandidateUserId = taskParam.getAssigneeOrCandidateUserId();

        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();

        taskService.delegateTask(task.getId(), assigneeOrCandidateUserId);
    }

    /**
     * 获取pageContext
     *
     * @Author xuyuxiang
     * @Date 2019/10/25 16:04
     **/
    private Page getPageContext() {
        return PageFactory.defaultPage();
    }
}
